<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>无人机控制测试页面 - 增强版</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        padding: 20px;
      }

      .container {
        max-width: 1400px;
        margin: 0 auto;
      }

      h1 {
        color: white;
        text-align: center;
        margin-bottom: 30px;
        text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
      }

      .grid {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
        gap: 20px;
        margin-bottom: 20px;
      }

      .card {
        background: white;
        border-radius: 12px;
        padding: 20px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
      }

      .card h2 {
        color: #333;
        margin-bottom: 20px;
        padding-bottom: 10px;
        border-bottom: 2px solid #667eea;
      }

      .card h3 {
        margin-top: 15px;
        margin-bottom: 10px;
        font-size: 16px;
        color: #555;
      }

      .form-group {
        margin-bottom: 15px;
      }

      label {
        display: block;
        margin-bottom: 5px;
        color: #555;
        font-weight: 500;
      }

      input,
      select {
        width: 100%;
        padding: 10px;
        border: 2px solid #e0e0e0;
        border-radius: 6px;
        font-size: 14px;
        transition: border-color 0.3s;
      }

      input:focus,
      select:focus {
        outline: none;
        border-color: #667eea;
      }

      button {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        border: none;
        padding: 12px 24px;
        border-radius: 6px;
        font-size: 16px;
        cursor: pointer;
        transition: transform 0.2s;
        width: 100%;
        margin-top: 10px;
      }

      button:hover {
        transform: translateY(-2px);
      }

      button:disabled {
        background: #ccc;
        cursor: not-allowed;
        transform: none;
      }

      .status {
        margin-top: 20px;
        padding: 15px;
        border-radius: 6px;
        background-color: #f5f5f5;
      }

      .status.success {
        background-color: #d4edda;
        color: #155724;
        border: 1px solid #c3e6cb;
      }

      .status.error {
        background-color: #f8d7da;
        color: #721c24;
        border: 1px solid #f5c6cb;
      }

      .status.info {
        background-color: #d1ecf1;
        color: #0c5460;
        border: 1px solid #bee5eb;
      }

      .telemetry-data {
        background: #f9f9f9;
        padding: 15px;
        border-radius: 6px;
        margin-top: 15px;
        max-height: 400px;
        overflow-y: auto;
      }

      .telemetry-item {
        display: flex;
        justify-content: space-between;
        padding: 8px 0;
        border-bottom: 1px solid #e0e0e0;
      }

      .telemetry-item:last-child {
        border-bottom: none;
      }

      .telemetry-label {
        font-weight: 600;
        color: #555;
      }

      .telemetry-value {
        color: #333;
        font-family: "Courier New", monospace;
      }

      .path-points {
        margin-top: 10px;
      }

      .path-point {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr auto;
        gap: 10px;
        margin-bottom: 10px;
      }

      .path-point input {
        padding: 8px;
      }

      .btn-remove {
        background: #dc3545;
        padding: 8px 12px;
      }

      .btn-add {
        background: #28a745;
        margin-top: 10px;
      }

      .btn-secondary {
        background: #6c757d;
      }

      pre {
        background: #2d2d2d;
        color: #f8f8f2;
        padding: 15px;
        border-radius: 6px;
        overflow-x: auto;
        font-size: 13px;
        line-height: 1.5;
      }

      .loading {
        display: inline-block;
        width: 20px;
        height: 20px;
        border: 3px solid rgba(255, 255, 255, 0.3);
        border-radius: 50%;
        border-top-color: #fff;
        animation: spin 1s ease-in-out infinite;
      }

      @keyframes spin {
        to {
          transform: rotate(360deg);
        }
      }

      .badge {
        display: inline-block;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 600;
        margin-left: 10px;
      }

      .badge-new {
        background-color: #28a745;
        color: white;
      }

      .badge-updated {
        background-color: #ffc107;
        color: #333;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>🚁 无人机控制测试面板 (增强版 v2.0)</h1>

      <div class="grid">
        <!-- 连接配置 -->
        <div class="card">
          <h2>⚙️ 连接配置</h2>
          <div class="form-group">
            <label>API 基础地址:</label>
            <input
              type="text"
              id="apiBase"
              value="http://localhost:3002"
              placeholder="http://localhost:3002"
            />
          </div>
          <div class="form-group">
            <label>无人机 ID:</label>
            <input type="text" id="droneId" value="uav_1" placeholder="uav_1" />
          </div>
          <div class="form-group">
            <label>认证令牌 (可选):</label>
            <input type="text" id="authToken" placeholder="Bearer token..." />
          </div>
          <button onclick="testConnection()">测试连接</button>
          <div id="connectionStatus" class="status" style="display: none"></div>
        </div>

        <!-- 遥测数据 -->
        <div class="card">
          <h2>📊 遥测数据</h2>
          <div class="form-group">
            <label>数据类型:</label>
            <select id="telemetryType">
              <option value="all">所有数据</option>
              <option value="pose">位置姿态</option>
              <option value="twist">速度</option>
              <option value="battery">电池</option>
              <option value="gps">GPS</option>
              <option value="imu">IMU</option>
              <option value="batch">批量数据</option>
            </select>
          </div>
          <button onclick="getTelemetry()">获取遥测数据</button>
          <button onclick="startMonitoring()">开始实时监控</button>
          <button onclick="stopMonitoring()">停止监控</button>
          <div class="telemetry-data" id="telemetryData"></div>
        </div>

        <!-- 基础控制 -->
        <div class="card">
          <h2>🎮 基础控制</h2>

          <h3>起飞</h3>
          <div class="form-group">
            <label>高度 (米):</label>
            <input type="number" id="takeoffHeight" value="10" step="0.5" />
          </div>
          <div class="form-group">
            <label>速度 (米/秒):</label>
            <input type="number" id="takeoffSpeed" value="1" step="0.1" />
          </div>
          <button onclick="takeoff()">起飞</button>

          <h3>降落</h3>
          <div class="form-group">
            <label>速度 (米/秒):</label>
            <input type="number" id="landSpeed" value="1" step="0.1" />
          </div>
          <button onclick="land()">降落</button>

          <h3>解锁/锁定</h3>
          <div class="form-group">
            <label>状态:</label>
            <select id="armingState">
              <option value="true">解锁</option>
              <option value="false">锁定</option>
            </select>
          </div>
          <button onclick="setArmingState()">设置解锁状态</button>
        </div>

        <!-- 导航控制 -->
        <div class="card">
          <h2>🗺️ 导航控制</h2>

          <h3>前往位置</h3>
          <div class="form-group">
            <label>X坐标 (米):</label>
            <input type="number" id="gotoX" value="10" step="1" />
          </div>
          <div class="form-group">
            <label>Y坐标 (米):</label>
            <input type="number" id="gotoY" value="10" step="1" />
          </div>
          <div class="form-group">
            <label>Z坐标/高度 (米):</label>
            <input type="number" id="gotoZ" value="10" step="0.5" />
          </div>
          <div class="form-group">
            <label>速度 (米/秒):</label>
            <input type="number" id="gotoSpeed" value="3" step="0.5" />
          </div>
          <button onclick="gotoPosition()">前往位置</button>
        </div>

        <!-- 路径跟随 -->
        <div class="card">
          <h2>🛤️ 路径跟随</h2>
          <div class="form-group">
            <label>飞行速度 (米/秒):</label>
            <input type="number" id="pathSpeed" value="3" step="0.5" />
          </div>
          <div class="path-points" id="pathPoints">
            <div class="path-point">
              <input type="number" placeholder="X" value="0" step="1" />
              <input type="number" placeholder="Y" value="0" step="1" />
              <input type="number" placeholder="Z" value="10" step="0.5" />
              <button class="btn-remove" onclick="removePathPoint(this)">
                删除
              </button>
            </div>
            <div class="path-point">
              <input type="number" placeholder="X" value="10" step="1" />
              <input type="number" placeholder="Y" value="0" step="1" />
              <input type="number" placeholder="Z" value="10" step="0.5" />
              <button class="btn-remove" onclick="removePathPoint(this)">
                删除
              </button>
            </div>
          </div>
          <button class="btn-add" onclick="addPathPoint()">添加航点</button>
          <button onclick="followPath()">执行路径</button>
        </div>

        <!-- 实时位姿控制 (新增) -->
        <div class="card">
          <h2>🎯 实时位姿控制 <span class="badge badge-new">NEW</span></h2>
          <p style="color: #666; font-size: 13px; margin-bottom: 15px">
            适用于高频实时控制（10Hz+），如手动遥控、轨迹跟踪等
          </p>

          <h3>位置设置</h3>
          <div class="form-group">
            <label>X坐标 (米):</label>
            <input type="number" id="poseX" value="0" step="0.1" />
          </div>
          <div class="form-group">
            <label>Y坐标 (米):</label>
            <input type="number" id="poseY" value="0" step="0.1" />
          </div>
          <div class="form-group">
            <label>Z坐标/高度 (米):</label>
            <input type="number" id="poseZ" value="10" step="0.1" />
          </div>
          <div class="form-group">
            <label>坐标系:</label>
            <select id="poseFrameId">
              <option value="map">map (全局坐标系)</option>
              <option value="base_link">base_link (机体坐标系)</option>
            </select>
          </div>
          <button onclick="publishPose()">发布位姿 (单次)</button>
          <button class="btn-secondary" onclick="startPoseStream()">
            开始连续发布 (10Hz)
          </button>
          <button class="btn-secondary" onclick="stopPoseStream()">
            停止连续发布
          </button>
          <div
            id="poseStreamStatus"
            style="margin-top: 10px; font-size: 13px; color: #666"
          ></div>
        </div>

        <!-- 高级服务 -->
        <div class="card">
          <h2>⚡ 高级服务</h2>

          <h3>控制模式设置 <span class="badge badge-updated">UPDATED</span></h3>
          <div class="form-group">
            <label>控制模式:</label>
            <select id="controlMode">
              <option value="0">UNSET (未设置)</option>
              <option value="1">HOVER (悬停)</option>
              <option value="2">POSITION (位置)</option>
              <option value="3">SPEED (速度)</option>
              <option value="4">SPEED_IN_A_PLANE (平面速度)</option>
              <option value="5">ATTITUDE (姿态)</option>
              <option value="6">ACRO (特技)</option>
              <option value="7">TRAJECTORY (轨迹)</option>
            </select>
          </div>
          <div class="form-group">
            <label>参考坐标系 (可选):</label>
            <select id="referenceFrame">
              <option value="">默认</option>
              <option value="0">UNDEFINED (未定义)</option>
              <option value="1">LOCAL_ENU (本地 ENU)</option>
              <option value="2">BODY_FLU (机体 FLU)</option>
              <option value="3">GLOBAL_LAT_LONG (全局经纬)</option>
            </select>
          </div>
          <div class="form-group">
            <label>偏航模式 (可选):</label>
            <select id="yawMode">
              <option value="">默认</option>
              <option value="0">KEEP_YAW (保持偏航)</option>
              <option value="1">PATH_FACING (朝向路径)</option>
              <option value="2">FIXED_YAW (固定偏航)</option>
            </select>
          </div>
          <button onclick="setControlMode()">设置控制模式</button>

          <h3>平台控制</h3>
          <button onclick="platformTakeoff()">平台起飞</button>
          <button onclick="platformLand()">平台降落</button>
        </div>

        <!-- 命令查询 -->
        <div class="card">
          <h2>🔍 命令结果查询</h2>
          <div class="form-group">
            <label>命令类型:</label>
            <select id="queryCommandType">
              <option value="takeoff">起飞 (takeoff)</option>
              <option value="land">降落 (land)</option>
              <option value="goto">前往 (goto)</option>
              <option value="follow_path">路径跟随 (follow_path)</option>
              <option value="set_arming_state">
                解锁状态 (set_arming_state)
              </option>
              <option value="set_control_mode">
                控制模式 (set_control_mode)
              </option>
              <option value="platform_takeoff">
                平台起飞 (platform_takeoff)
              </option>
              <option value="platform_land">平台降落 (platform_land)</option>
            </select>
          </div>
          <div class="form-group">
            <label>命令 ID (可选):</label>
            <input type="text" id="queryCmdId" placeholder="留空查询最新结果" />
          </div>
          <button onclick="queryCommandResult()">查询结果</button>
        </div>

        <!-- 响应日志 -->
        <div class="card" style="grid-column: 1 / -1">
          <h2>📝 响应日志</h2>
          <button onclick="clearLog()">清空日志</button>
          <button class="btn-secondary" onclick="exportLog()">导出日志</button>
          <pre id="responseLog">等待操作...</pre>
        </div>
      </div>
    </div>

    <script>
      // API 封装类
      class DroneAPI {
        constructor() {
          this.apiBase = "";
          this.droneId = "";
          this.token =
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc2NDA2MzU3MH0.m3VTayrD8ekKZUS6UlF4TVDPYWlrkE_vgaSEoNlvvz8";
        }

        init() {
          this.apiBase = document
            .getElementById("apiBase")
            .value.replace(/\/$/, "");
          this.droneId = document.getElementById("droneId").value;
          this.token =
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTc2NDA2MzU3MH0.m3VTayrD8ekKZUS6UlF4TVDPYWlrkE_vgaSEoNlvvz8";
        }

        async request(method, endpoint, body = null) {
          this.init();

          const headers = {
            "Content-Type": "application/json",
          };

          if (this.token) {
            headers["Authorization"] = this.token.startsWith("Bearer ")
              ? this.token
              : `Bearer ${this.token}`;
          }

          const options = {
            method,
            headers,
          };

          if (body) {
            options.body = JSON.stringify(body);
          }

          try {
            const response = await fetch(`${this.apiBase}${endpoint}`, options);
            const data = await response.json();

            if (!response.ok) {
              throw new Error(data.detail || `HTTP ${response.status}`);
            }

            return data;
          } catch (error) {
            throw error;
          }
        }

        // 遥测数据
        async getTelemetry(type = "all") {
          return this.request(
            "GET",
            `/api/drone-control/px4/pose/${this.droneId}?telemetry_type=${type}`
          );
        }

        // 起飞
        async takeoff(height, speed) {
          return this.request(
            "POST",
            "/api/drone-control/px4/control/takeoff",
            {
              drone_id: this.droneId,
              height,
              speed,
              cmd_id: `takeoff_${Date.now()}`,
            }
          );
        }

        // 降落
        async land(speed) {
          return this.request("POST", "/api/drone-control/px4/control/land", {
            drone_id: this.droneId,
            speed,
            cmd_id: `land_${Date.now()}`,
          });
        }

        // 前往位置
        async goto(x, y, z, speed) {
          return this.request("POST", "/api/drone-control/px4/control/goto", {
            drone_id: this.droneId,
            x,
            y,
            z,
            speed,
            yaw_mode: 0,
            yaw_angle: 0,
            cmd_id: `goto_${Date.now()}`,
          });
        }

        // 跟随路径
        async followPath(path, speed) {
          return this.request(
            "POST",
            "/api/drone-control/px4/control/follow_path",
            {
              drone_id: this.droneId,
              path,
              speed,
              yaw_mode: 0,
              yaw_angle: 0,
              mission_id: `mission_${Date.now()}`,
            }
          );
        }

        // 发布位姿 (新增)
        async publishPose(x, y, z, frameId = "map") {
          return this.request(
            "POST",
            "/api/drone-control/px4/control/publish_pose",
            {
              drone_id: this.droneId,
              pose: {
                position: { x, y, z },
                orientation: { x: 0, y: 0, z: 0, w: 1 },
              },
              frame_id: frameId,
              cmd_id: `pose_${Date.now()}`,
            }
          );
        }

        // 设置解锁状态
        async setArmingState(armed) {
          return this.request(
            "POST",
            "/api/drone-control/px4/service/set_arming_state",
            {
              drone_id: this.droneId,
              armed,
              cmd_id: `arm_${Date.now()}`,
            }
          );
        }

        // 设置控制模式 (更新)
        async setControlMode(
          controlMode,
          referenceFrame = null,
          yawMode = null
        ) {
          const payload = {
            drone_id: this.droneId,
            control_mode: controlMode,
            cmd_id: `mode_${Date.now()}`,
          };

          // 添加可选参数
          if (referenceFrame !== null && referenceFrame !== "") {
            payload.reference_frame = parseInt(referenceFrame);
          }
          if (yawMode !== null && yawMode !== "") {
            payload.yaw_mode = parseInt(yawMode);
          }

          return this.request(
            "POST",
            "/api/drone-control/px4/service/set_control_mode",
            payload
          );
        }

        // 平台起飞
        async platformTakeoff() {
          return this.request(
            "POST",
            "/api/drone-control/px4/service/platform_takeoff",
            {
              drone_id: this.droneId,
              enable: true,
              cmd_id: `platform_takeoff_${Date.now()}`,
            }
          );
        }

        // 平台降落
        async platformLand() {
          return this.request(
            "POST",
            "/api/drone-control/px4/service/platform_land",
            {
              drone_id: this.droneId,
              enable: true,
              cmd_id: `platform_land_${Date.now()}`,
            }
          );
        }

        // 查询命令结果
        async getCommandResult(commandType, cmdId = null) {
          const query = cmdId ? `?cmd_id=${cmdId}` : "";
          return this.request(
            "GET",
            `/api/drone-control/px4/command/result/${this.droneId}/${commandType}${query}`
          );
        }
      }

      const api = new DroneAPI();
      let monitoringInterval = null;
      let poseStreamInterval = null;
      let poseStreamCounter = 0;

      // 显示状态
      function showStatus(elementId, message, type = "info") {
        const element = document.getElementById(elementId);
        element.style.display = "block";
        element.className = `status ${type}`;
        element.textContent = message;
      }

      // 记录日志
      function log(data, title = "") {
        const logElement = document.getElementById("responseLog");
        const timestamp = new Date().toLocaleTimeString();
        const logEntry = `[${timestamp}] ${title}\n${JSON.stringify(
          data,
          null,
          2
        )}\n\n`;
        logElement.textContent = logEntry + logElement.textContent;
      }

      // 清空日志
      function clearLog() {
        document.getElementById("responseLog").textContent = "等待操作...";
      }

      // 导出日志
      function exportLog() {
        const logContent = document.getElementById("responseLog").textContent;
        const blob = new Blob([logContent], { type: "text/plain" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = `drone_control_log_${Date.now()}.txt`;
        a.click();
        URL.revokeObjectURL(url);
      }

      // 测试连接
      async function testConnection() {
        try {
          const data = await api.getTelemetry("pose");
          showStatus("connectionStatus", "连接成功！", "success");
          log(data, "连接测试成功");
        } catch (error) {
          showStatus("connectionStatus", `连接失败: ${error.message}`, "error");
          log({ error: error.message }, "连接测试失败");
        }
      }

      // 获取遥测数据
      async function getTelemetry() {
        try {
          const type = document.getElementById("telemetryType").value;
          const data = await api.getTelemetry(type);
          displayTelemetry(data);
          log(data, `获取遥测数据 (${type})`);
        } catch (error) {
          log({ error: error.message }, "获取遥测数据失败");
        }
      }

      // 显示遥测数据
      function displayTelemetry(data) {
        const container = document.getElementById("telemetryData");
        container.innerHTML = "";

        function renderObject(obj, prefix = "") {
          for (const [key, value] of Object.entries(obj)) {
            if (
              typeof value === "object" &&
              value !== null &&
              !Array.isArray(value)
            ) {
              renderObject(value, prefix ? `${prefix}.${key}` : key);
            } else {
              const item = document.createElement("div");
              item.className = "telemetry-item";
              const displayValue = Array.isArray(value)
                ? JSON.stringify(value)
                : value;
              item.innerHTML = `
                <span class="telemetry-label">${
                  prefix ? `${prefix}.${key}` : key
                }:</span>
                <span class="telemetry-value">${displayValue}</span>
              `;
              container.appendChild(item);
            }
          }
        }

        renderObject(data);
      }

      // 开始监控
      function startMonitoring() {
        if (monitoringInterval) {
          clearInterval(monitoringInterval);
        }

        monitoringInterval = setInterval(async () => {
          try {
            const data = await api.getTelemetry("all");
            displayTelemetry(data);
          } catch (error) {
            console.error("监控更新失败:", error);
          }
        }, 2000);

        log({ status: "started" }, "开始实时监控");
      }

      // 停止监控
      function stopMonitoring() {
        if (monitoringInterval) {
          clearInterval(monitoringInterval);
          monitoringInterval = null;
          log({ status: "stopped" }, "停止实时监控");
        }
      }

      // 起飞
      async function takeoff() {
        try {
          const height = parseFloat(
            document.getElementById("takeoffHeight").value
          );
          const speed = parseFloat(
            document.getElementById("takeoffSpeed").value
          );
          const data = await api.takeoff(height, speed);
          log(data, "起飞命令");
        } catch (error) {
          log({ error: error.message }, "起飞失败");
        }
      }

      // 降落
      async function land() {
        try {
          const speed = parseFloat(document.getElementById("landSpeed").value);
          const data = await api.land(speed);
          log(data, "降落命令");
        } catch (error) {
          log({ error: error.message }, "降落失败");
        }
      }

      // 前往位置
      async function gotoPosition() {
        try {
          const x = parseFloat(document.getElementById("gotoX").value);
          const y = parseFloat(document.getElementById("gotoY").value);
          const z = parseFloat(document.getElementById("gotoZ").value);
          const speed = parseFloat(document.getElementById("gotoSpeed").value);
          const data = await api.goto(x, y, z, speed);
          log(data, "GoTo命令");
        } catch (error) {
          log({ error: error.message }, "GoTo失败");
        }
      }

      // 设置解锁状态
      async function setArmingState() {
        try {
          const armed = document.getElementById("armingState").value === "true";
          const data = await api.setArmingState(armed);
          log(data, "设置解锁状态");
        } catch (error) {
          log({ error: error.message }, "设置解锁状态失败");
        }
      }

      // 发布位姿 (新增)
      async function publishPose() {
        try {
          const x = parseFloat(document.getElementById("poseX").value);
          const y = parseFloat(document.getElementById("poseY").value);
          const z = parseFloat(document.getElementById("poseZ").value);
          const frameId = document.getElementById("poseFrameId").value;
          const data = await api.publishPose(x, y, z, frameId);
          log(data, "发布位姿 (单次)");
        } catch (error) {
          log({ error: error.message }, "发布位姿失败");
        }
      }

      // 开始连续发布位姿
      function startPoseStream() {
        if (poseStreamInterval) {
          stopPoseStream();
        }

        poseStreamCounter = 0;
        const statusElement = document.getElementById("poseStreamStatus");
        statusElement.textContent = "正在连续发布位姿...";
        statusElement.style.color = "#28a745";

        poseStreamInterval = setInterval(async () => {
          try {
            const x = parseFloat(document.getElementById("poseX").value);
            const y = parseFloat(document.getElementById("poseY").value);
            const z = parseFloat(document.getElementById("poseZ").value);
            const frameId = document.getElementById("poseFrameId").value;

            await api.publishPose(x, y, z, frameId);
            poseStreamCounter++;
            statusElement.textContent = `已发布 ${poseStreamCounter} 次位姿 (10Hz)`;
          } catch (error) {
            console.error("位姿发布失败:", error);
            statusElement.textContent = `发布失败: ${error.message}`;
            statusElement.style.color = "#dc3545";
          }
        }, 100); // 10Hz = 100ms

        log({ status: "started", frequency: "10Hz" }, "开始连续发布位姿");
      }

      // 停止连续发布位姿
      function stopPoseStream() {
        if (poseStreamInterval) {
          clearInterval(poseStreamInterval);
          poseStreamInterval = null;
          const statusElement = document.getElementById("poseStreamStatus");
          statusElement.textContent = `已停止 (共发布 ${poseStreamCounter} 次)`;
          statusElement.style.color = "#666";
          log(
            { status: "stopped", total_count: poseStreamCounter },
            "停止连续发布位姿"
          );
        }
      }

      // 设置控制模式 (更新)
      async function setControlMode() {
        try {
          const controlMode = parseInt(
            document.getElementById("controlMode").value
          );
          const referenceFrame =
            document.getElementById("referenceFrame").value;
          const yawMode = document.getElementById("yawMode").value;

          const data = await api.setControlMode(
            controlMode,
            referenceFrame,
            yawMode
          );
          log(data, "设置控制模式");
        } catch (error) {
          log({ error: error.message }, "设置控制模式失败");
        }
      }

      // 平台起飞
      async function platformTakeoff() {
        try {
          const data = await api.platformTakeoff();
          log(data, "平台起飞");
        } catch (error) {
          log({ error: error.message }, "平台起飞失败");
        }
      }

      // 平台降落
      async function platformLand() {
        try {
          const data = await api.platformLand();
          log(data, "平台降落");
        } catch (error) {
          log({ error: error.message }, "平台降落失败");
        }
      }

      // 查询命令结果
      async function queryCommandResult() {
        try {
          const commandType = document.getElementById("queryCommandType").value;
          const cmdId = document.getElementById("queryCmdId").value || null;
          const data = await api.getCommandResult(commandType, cmdId);
          log(data, `查询命令结果 (${commandType})`);
        } catch (error) {
          log({ error: error.message }, "查询命令结果失败");
        }
      }

      // 路径点管理
      function addPathPoint() {
        const container = document.getElementById("pathPoints");
        const point = document.createElement("div");
        point.className = "path-point";
        point.innerHTML = `
          <input type="number" placeholder="X" value="0" step="1">
          <input type="number" placeholder="Y" value="0" step="1">
          <input type="number" placeholder="Z" value="10" step="0.5">
          <button class="btn-remove" onclick="removePathPoint(this)">删除</button>
        `;
        container.appendChild(point);
      }

      function removePathPoint(btn) {
        btn.parentElement.remove();
      }

      // 执行路径
      async function followPath() {
        try {
          const points = document.querySelectorAll(".path-point");
          const path = Array.from(points).map((point) => {
            const inputs = point.querySelectorAll("input");
            return {
              x: parseFloat(inputs[0].value),
              y: parseFloat(inputs[1].value),
              z: parseFloat(inputs[2].value),
            };
          });

          const speed = parseFloat(document.getElementById("pathSpeed").value);
          const data = await api.followPath(path, speed);
          log(data, "路径跟随命令");
        } catch (error) {
          log({ error: error.message }, "路径跟随失败");
        }
      }

      // 页面加载时停止所有定时器
      window.addEventListener("beforeunload", () => {
        stopMonitoring();
        stopPoseStream();
      });
    </script>
  </body>
</html>
